package com.itheima.excel.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.util.MapUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.fastjson.JSON;
import com.itheima.excel.entity.OperationDTO;
import com.itheima.excel.entity.User;
import com.itheima.excel.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;

@RestController
@RequestMapping("/excel")
@Slf4j
public class ExcelController {

    @Autowired
    UserService userService;

    /**
     * 文件上传: 将上传的Excel中的数据保存到数据库表
     */
    @PostMapping("upload")
    @ResponseBody
    public String upload(MultipartFile file) throws IOException {
        userService.read(file);
        return "success";
    }

    /**
     * 文件下载并且失败的时候返回json（默认失败了会返回一个有部分数据的Excel）
     * 将表中的数据以Excel形式下载
     * @since 2.1.1
     */
    @GetMapping("download")
    public void downloadFailedUsingJson(HttpServletResponse response) throws IOException {
        // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("测试EasyExcel-"+LocalDate.now(), "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            // 这里需要设置不关闭流
            EasyExcel.write(response.getOutputStream(), User.class).autoCloseStream(Boolean.FALSE).sheet("模板")
                    .doWrite(userService.list());
        } catch (Exception e) {
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, String> map = MapUtils.newHashMap();
            map.put("status", "failure");
            map.put("message", "下载文件失败" + e.getMessage());
            response.getWriter().println(JSON.toJSONString(map));
        }
    }

    /**
     * 根据模板填充数据并下载
     * @param response
     * @throws IOException
     */
    @GetMapping("/template/download")
    public void downloadTemplate(HttpServletResponse response) throws IOException {
        // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
        // {} 代表普通变量 {.} 代表是list的变量
        //模板路径
        String templatePath = new ClassPathResource("excel/运营数据报表模板.xlsx").getFile().getAbsolutePath();

        //Excel下载需要设置的响应格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");

        //设置下载文件名 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("运营数据Excel-"+LocalDate.now(), "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

        // 填充模板并下载
        try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(templatePath).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行，然后下面的数据往后移动。默认 是false，会直接使用下一行，如果没有则创建。
            // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了，所以慎用
            // 简单的说 如果你的模板有list,且list不是最后一行，下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存
            // 如果数据量大 list不是最后一行 参照下一个
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            excelWriter.fill(data(),fillConfig, writeSheet);
            excelWriter.fill(data(),fillConfig,  writeSheet);
            //单个表格需要的数据
            Map<String, Object> map = MapUtils.newHashMap();
            map.put("beginTime",LocalDate.now().minusDays(5).toString()); //开始时间
            map.put("endTime",LocalDate.now().toString()); //结束时间
            map.put("turnover", 8888.88);  //营业额
            map.put("orderCompletionRate", 0.99); //订单完成率
            map.put("newUsers", 600); //新增用户数
            map.put("validOrderCount", 68); //有效订单数
            map.put("unitPrice", 196.28); //平均客单价
            map.put("total",999); //总计

            excelWriter.fill(map, writeSheet);

            //关闭流
            excelWriter.finish();
        }catch (Exception e){
            e.printStackTrace();
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, String> map = MapUtils.newHashMap();
            map.put("status", "failure");
            map.put("message", "下载文件失败" + e.getMessage());
            response.getWriter().println(JSON.toJSONString(map));
        }
    }

    private List<OperationDTO> data() {
        ArrayList<OperationDTO> list = new ArrayList<>();
        Random random = new Random(10);
        for (int i = 1; i <= 5; i++) {
            OperationDTO operationDTO = OperationDTO.builder()
                    .date(LocalDate.now().plusDays(i).toString())
                    .turnover(Double.valueOf(random.nextInt(1000) + ""))
                    .validOrderCount(random.nextInt(100))
                    .orderCompletionRate(Math.random())
                    .unitPrice(Double.valueOf(new DecimalFormat("#.0000").format(1000.0/i)))
                    .newUsers(random.nextInt(100)+1)
                    .build();
            list.add(operationDTO);
        }
        return list;
    }
}
